package cn.kioye.secretbmp.utils;

import java.awt.image.BufferedImage;


/**
 * Bmp无压缩24位图，数据的注入和读取
 * @author Caolijian
 *
 */
public class BmpUtil {
	/**
	 *像素位置信息，和像素信息
	 * int l占4个字节，其3字节分别代表RGB
	 */
	public static class Position {
		public int x = 0, y = 0, l = 1;
		public Position() {
		}
		public Position(int x, int y, int l) {
			super();
			this.x = x;
			this.y = y;
			this.l = l;
		}
	}
	/**
	 * 读取隐藏的数据
	 * @param bi 图片的缓存区
	 * @param p 像素位置
	 * @param readSize 读取字节数
	 * @return byte数组
	 */
	public static byte[] read(BufferedImage bi, Position p, int readSize) {
		int oubtpos = 0,oubtIndex = 0;
		boolean isDone = false;
		byte[] inbt=new byte[readSize];
		for (; p.y < bi.getHeight(); p.y++) {
			for (; p.x < bi.getWidth() || (p.x = 0) != 0; p.x++) {

				if (isDone) {
					return inbt;
				}
				int rgb = bi.getRGB(p.x, p.y);
				
//				System.out.println(Integer.toBinaryString(rgb)+"<--rgb");
				
				byte[] int2byte = ByteUtil.int2byte(rgb);
				for (; p.l < 4 || (p.l = 1) != 1; p.l++) {
					if (isDone) {
						break;
					}
					if (1== (int2byte[p.l] & 1)) {
						inbt[oubtpos]=(byte) (inbt[oubtpos]|(1<<oubtIndex));
					}
					if ((++oubtIndex)==8) {
						oubtIndex=0;
						if ((++oubtpos)==readSize) {
							isDone = true;
						}
					}
				}
				if (isDone && p.l != 1) {
					return inbt;
				}
				
			}
		}
		return inbt;
	}
	/**
	 * 注入要隐藏的数据
	 * @param bi 图片的缓存区
	 * @param p 像素位置
	 * @param inbt 要写入的byte数组
	 * @param inSize 写入字节数
	 * @return 写完后的下一个像素位置
	 */
	public static Position inject(BufferedImage bi, Position p, byte[] inbt, int inSize) {
		int inbtIndex = 0, inbtpos = 0;
		boolean isDone = false;

		//防越界循环
		for (; p.y < bi.getHeight(); p.y++) {
			for (; p.x < bi.getWidth() || (p.x = 0) != 0; p.x++) {
				//终止拦截[放此处为了让指针指向下一像素]
				if (isDone) {
					return p;
				}
				//获得像素，并分离成3字节
				int rgb = bi.getRGB(p.x, p.y);
				byte[] int2byte = ByteUtil.int2byte(rgb);

				//判断该像素是否已经填充满信息
				for (; p.l < 4 || (p.l = 1) != 1; p.l++) {
					if (isDone) {
						break;
					}
					// 进行数据偏移，再合并在图像像素中
					// 原理：用偏移的数和图像像素 '&' 合并，得知原像素位的值，然后进行处理
					if ((1 << inbtIndex) == (inbt[inbtpos] & (1 << inbtIndex))) {
						int2byte[p.l] = (byte) (int2byte[p.l] | (1));
					} else {
						int2byte[p.l] = (byte) (int2byte[p.l] & (254));
					}
					// 判断是否将数据写完
					if ((++inbtIndex) == 8) {
						inbtIndex = 0;
						if ((++inbtpos) == inSize) {
							isDone = true;
						}
					}
				}
				rgb = ByteUtil.bytes2Int(int2byte);
				// 保存回图像流
				bi.setRGB(p.x, p.y, rgb);
				if (isDone && p.l != 1) {
					return p;
				}
			}
		}
		return p;
	}
}
